import React, { KeyboardEvent, useEffect, useRef, useState } from 'react';
import styles from './index.module.css';
import CustomIcon from '@/components/CustomIcon';
import { Message } from '@alicloudfe/components';
import ChatHistory from './ChatHistory';
import { getAnswer, getModelList } from '@/AI/apis';
import dayjs from 'dayjs';
import uploadFile from '@/utils/upload';
import ImagePreview from '../ImagePreview';
import ChatInputArea from '../ChatInputArea';
import ChatNoConfigPrompt from '../ChatNoConfigPrompt';

import { FORMAT_DATE_TIME, IChatItem, IHistory, IModel } from '@/AI/useAI';
import AtomIntl from '@/utils/intl';
import AtomLogo from '@/assets/atom.png';
import useStorageState from '@/AI/utils/storageHooks';
import ChatList from '../ChatList';
import { IRequestGetAnswer, PictureQuesionList } from '../ai';

interface IProps {
  visible?: boolean;
  onVisibleChange?: (visible: boolean) => void;
}

const storageKeyMap = {
  currentModelInfo: 'ai_current_model_info',
};

export default function (props: IProps) {
  const {
    visible,
    onVisibleChange = () => {},
  } = props;

  const [innerVisible, setInnerVisilbe] = useState(false);
  useEffect(() => {
    if (innerVisible) {
      // 每次开启窗口，加载一次已设置的 apiKey
      // 防止新设置的模型不在列表里
      getUserHaveSetModelList();

      scrollToChatContentBottom();
    }
  }, [innerVisible]);
  const updateInnerVisible = (value: boolean) => {
    setInnerVisilbe(value);
    onVisibleChange(value);
  };
  const hideWindow = () => {
    updateInnerVisible(false);
  };
  useEffect(() => {
    setInnerVisilbe(visible);
  }, [visible]);

  const [selectedFile, setSelectedFile] = useState<{
    fileObj: File;
    type: 'img' | 'file';
    ossAddr?: string;
  }>(null);
  const selectedFileRef = useRef<any>();
  useEffect(() => {
    selectedFileRef.current = selectedFile;
  }, [selectedFile]);

  const [previewingImg, setPreviewingImg] = useState('');
  const openImgPreview = (imgSrc: string) => {
    setPreviewingImg(imgSrc);
  };

  const hideImgPreview = () => {
    setPreviewingImg('');
  };


  const [chatList, updateChatList] = useStorageState<IChatItem[]>(
    `${storageKeyMap.currentModelInfo}_chatList`,
    [],
    'sessionStorage',
  );

  const [chatHistory, updateChatHistory, chatHistoryRef] = useStorageState<IHistory[]>(
    `${storageKeyMap.currentModelInfo}_chatHistory`,
    [],
    'sessionStorage',
  );

  const [questionList, updateQuestionList, questionListRef] = useStorageState<string[]>(
    `${storageKeyMap.currentModelInfo}_questionList`,
    [],
    'localStorage',
  );

  const onSelectHistoryQuestion = (question: string) => {
    clearCurrentUserInput();
    setUserQuestion(question);
    setHistoryVisible(false);
  };

  const initChatHistoryByModelInfo = (modelInfo: IModel) => {
    const baseStorageKey = `${storageKeyMap.currentModelInfo}`;

    const storageKeyChatList = `${baseStorageKey}_chatList`;
    const savedChatListStr = sessionStorage.getItem(storageKeyChatList);
    const storageKeyChatHistory = `${baseStorageKey}_chatHistory`;
    const savedChatHistoryStr = sessionStorage.getItem(storageKeyChatHistory);

    if (!savedChatListStr || !savedChatHistoryStr) {
      updateChatList([{
        modelId: modelInfo.id,
        modelName: modelInfo.name,
        version: modelInfo.version,
        icon: modelInfo.icon || AtomLogo,
        customModelName: modelInfo.customModelName,
        time: dayjs().format(FORMAT_DATE_TIME),
        type: 'answer',
        content: AtomIntl.get('AI_Chat_ChatWindow_index_我能帮你做什么？'),
      }]);
      updateChatHistory([]);
      scrollToChatContentBottom();
    } else {
      try {
        const savedChatList = JSON.parse(savedChatListStr);
        const savedChatHistory = JSON.parse(savedChatHistoryStr);

        updateChatList(savedChatList);
        updateChatHistory(savedChatHistory);
        scrollToChatContentBottom();
      } catch (err) {
        console.log('chat infos parse error. ', err);
      }
    }


    const storageKeyQuestionList = `${baseStorageKey}_questionList`;
    const savedQuestionListStr = localStorage.getItem(storageKeyQuestionList);

    if (!savedQuestionListStr) {
      updateQuestionList([]);
    } else {
      try {
        const savedList = JSON.parse(savedQuestionListStr);
        updateQuestionList(savedList);
      } catch (err) {
        console.log('question list parse error. ', err);
      }
    }
  };

  const [historyVisible, setHistoryVisible] = useState(false);


  const [haveSetModelList, setHaveSetModelList] = useState<IModel[]>([]);
  const getUserHaveSetModelList = () => {
    getModelList().then((res) => {
      const data = res || [];
      const result: IModel[] = [];
      data.forEach((item: any) => {
        const {
          versionList,
        } = item;
        versionList.forEach((versionObj: {
          version: string;
          customModelName: string;
        }) => {
          const temp = {
            ...item,
            version: versionObj.version,
            customModelName: versionObj.customModelName,
          };
          delete temp.versionList;
          result.push(temp);
        });
      });
      setHaveSetModelList(result);
    });
  };
  useEffect(() => {
    getUserHaveSetModelList();
  }, []);
  const hasConfig = !!haveSetModelList.length;

  const [currentModel, setCurrentModel] = useState<IModel>();
  const initCurrentModel = () => {
    if (!haveSetModelList.length) {
      return;
    }

    if (currentModel) {
      // 如果已经选择模型了，证明不是第一次
      // 不走后续初始化逻辑
      return;
    }

    const initByFirstModel = () => {
      const firstModel = haveSetModelList[0];
      changeCurrentModel(firstModel);
      initChatHistoryByModelInfo(firstModel);
    };
    const modelInfoStr = localStorage.getItem(storageKeyMap.currentModelInfo);
    if (!modelInfoStr) {
      initByFirstModel();
      return;
    }
    const savedCurrentModel = JSON.parse(modelInfoStr);
    const existIn = haveSetModelList.find((i) => i.id === savedCurrentModel.id);
    if (!existIn) {
      initByFirstModel();
      return;
    }
    changeCurrentModel(existIn);
    initChatHistoryByModelInfo(existIn);
  };

  useEffect(() => {
    initCurrentModel();
  }, [haveSetModelList]);

  const saveCurrentModelInfo = (modelInfo: IModel) => {
    localStorage.setItem(storageKeyMap.currentModelInfo, JSON.stringify(modelInfo));
  };
  const changeCurrentModel = (modelInfo: IModel) => {
    setCurrentModel(modelInfo);

    saveCurrentModelInfo(modelInfo);
    // saveCurrentChatHistory();

    clearCurrentUserInput();
  };


  const [uploading, setUploading] = useState(false);
  const uploadFileToOSS = async (file: File) => {
    const parts = file.name.split('.');
    parts.pop();
    try {
      setUploading(true);
      const res = await uploadFile({
        file,
        name: parts.join('.'),
      }) as {
        name: string;
        url: string;
      };
      setUploading(false);
      setSelectedFile({
        ...selectedFileRef.current,
        ossAddr: res.url,
      });
    } catch (err) {
      setUploading(false);
    }
  };


  const [userQuestion, setUserQuestion] = useState('');
  const [isAsking, setIsAsking] = useState(false);
  const disableSendButton = isAsking || uploading || !currentModel || !userQuestion.trim();

  const clearCurrentUserInput = () => {
    setUserQuestion('');
    setSelectedFile(null);
  };


  const contentAreaRef = useRef<HTMLDivElement>();
  const scrollToChatContentBottom = () => {
    if (!contentAreaRef.current) {
      return;
    }

    setTimeout(() => {
      contentAreaRef.current.scrollTop = contentAreaRef.current.scrollHeight;
    }, 50);
  };

  const onInputAreaKeyUp = (event: KeyboardEvent) => {
    if (event.key === 'Enter') {
      if (!disableSendButton) {
        sendQuestion();
      }
      event.preventDefault();
      event.stopPropagation();
      return false;
    }
  };

  const currentRequest = useRef<any>();
  const sendQuestion = () => {
    const params: IRequestGetAnswer = {
      modelId: currentModel.id,
      version: currentModel.version,
      targetType: 1,
    };
    if (currentModel.pictureSupport || currentModel.docSupport) {
      const pictureQuesionList: PictureQuesionList[] = [];
      chatHistory.forEach((aHistory) => {
        const user: PictureQuesionList = {
          text: aHistory.user,
          role: 'user',
          image: '',
        };
        pictureQuesionList.push(user);
        if (aHistory.bot) {
          const bot: PictureQuesionList = {
            text: aHistory.bot,
            role: 'assistant',
            image: '',
          };
          pictureQuesionList.push(bot);
        }
      });
      pictureQuesionList.push({
        image: selectedFile?.ossAddr || '',
        text: userQuestion,
        role: 'user',
      });
      params.pictureQuesionList = pictureQuesionList;
    } else if (currentModel.charactersSupport) {
      params.prompt = userQuestion;
      params.history = chatHistory as any;
    } else {
      Message.notice(AtomIntl.get('AI_Chat_ChatWindow_index_当前模型不支持提问'));
      return;
    }
    const newQuestionItem: IChatItem = {
      modelId: currentModel.id,
      modelName: currentModel.name,
      version: currentModel.version,
      customModelName: currentModel.customModelName,
      type: 'question',
      time: dayjs().format(FORMAT_DATE_TIME),
      content: userQuestion,
      image: selectedFile?.ossAddr,
    };
    const aHistory: IHistory = {
      user: userQuestion,
      bot: '',
      image: selectedFile?.ossAddr,
    };

    questionListRef.current.unshift(userQuestion);
    updateQuestionList([...questionListRef.current]);
    const list = [...chatList];
    list.push(newQuestionItem);
    const newAnswerItem: IChatItem = {
      modelId: currentModel.id,
      modelName: currentModel.name,
      version: currentModel.version,
      icon: currentModel.icon,
      customModelName: currentModel.customModelName,
      type: 'loading',
      time: dayjs().format(FORMAT_DATE_TIME),
      content: '',
    };
    updateChatList([
      ...list,
      newAnswerItem,
    ]);
    clearCurrentUserInput();
    scrollToChatContentBottom();
    setIsAsking(true);

    const {
      source,
      request,
    } = getAnswer(params, (resp) => {
      const stopped = resp?.output?.finish_reason === 'stop';
      if (stopped) {
        setIsAsking(false);
      }
      newAnswerItem.type = stopped ? 'answer' : 'answerLoading';
      newAnswerItem.content = resp?.output?.text;
      aHistory.bot = newAnswerItem.content;
      const temp = chatHistoryRef.current.filter((i) => i != aHistory);
      temp.push(aHistory);
      updateChatHistory([...temp]);
      updateChatList([
        ...list,
        newAnswerItem,
      ]);
      scrollToChatContentBottom();
    });
    request.then(() => {
      setIsAsking(false);
    }).catch(() => {
      setIsAsking(false);
    });
    currentRequest.current = source;
  };


  const maskRef = useRef(null);
  return innerVisible && (
    <div
      className={styles.chatWindowMask}
      ref={maskRef}
      onClickCapture={(event) => {
        if (event.target === maskRef.current) {
          hideWindow();
        }
      }}
    >
      <div
        className={styles.chatWindowContaienr}
        id="atomgit-ai-chat-container"
      >
        <div className={styles.chatTitleLine}>
          <div className={styles.modelInfos}>
            <div className={styles.modelIconContainer}>
              <img
                className={styles.modelIcon}
                src={currentModel ? currentModel.icon : AtomLogo}
              />
            </div>
            <div className={styles.modelName}>
              {currentModel ? (
                `${currentModel.name} ${currentModel.version}`
              ) : AtomIntl.get('AI_Chat_ChatWindow_index_Atomgit 助手')}
            </div>
          </div>

          <div
            className={styles.operation}
            onClick={() => hideWindow()}
          >
            <CustomIcon type="icon-projectOdelete2-fill" />
          </div>
        </div>
        <div
          className={styles.contentArea}
          ref={contentAreaRef}
        >
          <div className={styles.contentList}>
            {
              hasConfig ? (
                <ChatList
                  chatList={chatList}
                  currentRequest={currentRequest}
                  setIsAsking={setIsAsking}
                  updateChatList={updateChatList}
                  setPreviewingImg={setPreviewingImg}
                  setUserQuestion={setUserQuestion}
                />
              ) : (
                <ChatNoConfigPrompt />
              )
            }
          </div>
        </div>
        {
          hasConfig && (
            <ChatInputArea
              currentModel={currentModel}
              haveSetModelList={haveSetModelList}
              changeCurrentModel={changeCurrentModel}
              selectedFile={selectedFile}
              setSelectedFile={setSelectedFile}
              uploadFileToOSS={uploadFileToOSS}
              uploading={uploading}
              setHistoryVisible={setHistoryVisible}
              openImgPreview={() => {
                openImgPreview(selectedFile?.ossAddr);
              }}
              userQuestion={userQuestion}
              setUserQuestion={setUserQuestion}
              onInputAreaKeyUp={onInputAreaKeyUp}
              disableSendButton={disableSendButton}
              sendQuestion={sendQuestion}
            />
          )
        }

        <ChatHistory
          visible={historyVisible}
          questionList={questionList}
          setQuestionList={updateQuestionList}
          onSelect={onSelectHistoryQuestion}
          hideWindow={() => {
            setHistoryVisible(false);
            hideWindow();
          }}
          closeHistory={() => {
            setHistoryVisible(false);
          }}
        />
      </div>

      {
        previewingImg && (
          <ImagePreview
            onHide={hideImgPreview}
            src={previewingImg}
          />
        )
      }
    </div>
  );
}

